#include "dist.h"

#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>

#include <unistd.h>
#include <math.h>

int simi::distance(const std::string fic1, const std::string fic2) {
    using namespace std;

    int tailleA, tailleB;

    ifstream A(fic1.c_str());
    ifstream B(fic2.c_str());

    string buff;
    istringstream lineA;
    istringstream lineB;
    getline(A, buff);
    A >> tailleA;
    getline(A, buff);

    getline(B, buff);
    B >> tailleB;
    getline(B, buff);


    double **matrice;

    matrice = new double*[tailleA];

    for (int i = 0; i < tailleA; i++) {
        matrice[i] = new double[tailleB];
        for (int j = 0; j < tailleB; ++j) {
            matrice[i][j] = 0.;
        }
    }

    //pour toutes les lignes (vecteurs) du fichier A
    for (int indSiftA = 0; indSiftA < tailleA; ++indSiftA) {
        getline(A, buff);
        lineA.clear();
        lineA.str(buff);

        if (indSiftA != 0) {
            getline(B, buff);
            B >> tailleB;
            getline(B, buff);
        }

        // On saute les 5 premières valeurs
        double valeurA;
        for (unsigned i = 0; i < 5; ++i) {
            lineA >> valeurA;
        }

        //Pour chaque valeur du vecteur sift
        vector<double> siftA;
        //cerr << "### " << lineA.str() << endl;
        while (lineA >> valeurA) {
            //cerr << valeurA << " , ";
            siftA.push_back(valeurA);
        }
        /*cerr << endl;
        if(siftA.size() != 128) {
            cerr << "Sift " << indSiftA << " de A qui ne fait pas 128 : "
                    << siftA.size() << endl;
        }*/
        getline(lineA, buff);

        //cerr << endl << endl;

        // Pour chaque sift de B
        for (int indSiftB = 0; indSiftB < tailleB; ++indSiftB) {


            getline(B, buff);
            lineB.clear();
            lineB.str(buff);

            // On saute les 5 premières valeurs
            double valeurB;
            for (unsigned i = 0; i < 5; ++i) {
                lineB >> valeurB;
            }

            long double calcul = 0.;

            for (int j = 0; j < 128; ++j) {
                lineB >> valeurB;
                calcul += pow(fabs(siftA[j] - valeurB), 2);
                //cerr << '(' << siftA[j] << " - " << valeurB << "), ";
            }
            //cerr << endl;
            getline(lineB, buff);

            matrice[indSiftA][indSiftB] = sqrt(calcul);

            //cout << matrice[indSiftA][indSiftB] << " - ";

        }
        //cout << endl;
        B.seekg(0, ios::beg);
    }

    A.close();
    B.close();

    //On affiche la matrice
    /*for (int i = 0; i < tailleA; i++) {
      cout << i << " : ";
      for(int j = 0; j < tailleB; ++j) {
        cout << matrice[i][j] << ' ';
      }
      cout << endl;
    }*/

    // On cherche les plus similaires
    int simiA[tailleA];
    int simiB[tailleB];

    // (a) On cherche les sifts de B les plus proches des sifts de A
    for (int i = 0; i < tailleA; ++i) {
        simiA[i] = 0;
        for (int j = 1; j < tailleB; ++j) {
            if (matrice[i][j] < matrice[i][simiA[i]]) {
                simiA[i] = j;
            }
        }
    }


    // (b) On cherche les sifts de A les plus proches des sifts de B
    for (int i = 0; i < tailleB; ++i) {
        simiB[i] = 0;
        for (int j = 1; j < tailleA; ++j) {
            if (matrice[j][i] < matrice[simiB[i]][i]) {
                simiB[i] = j;
            }
        }
    }

    // (c) On garde les valeurs les plus grandes
    int similarite = 0;
    for (int i = 0; i < tailleA; ++i) {
        //if (i == simiB[simiA[i]] && matrice[i][simiA[i]] < 0.5 * NORM) {
        if (i == simiB[simiA[i]]) {
            ++similarite;
        }
    }

    // On libère les ressources
    for (int i = 0; i < tailleA; i++) {
        delete [] matrice[i];
    }
    delete [] matrice;

    return similarite;
}
